package org.light.shiroauth;

import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

import org.light.core.LayoutComb;
import org.light.core.ReportComb;
import org.light.domain.Domain;
import org.light.domain.Dropdown;
import org.light.domain.Field;
import org.light.domain.ManyToMany;
import org.light.domain.Statement;
import org.light.domain.StatementList;
import org.light.domain.Util;
import org.light.easyuilayouts.widgets.Nav;
import org.light.utils.DomainUtil;
import org.light.utils.StringUtil;

public class ShiroConfigGenerator extends Util{
	protected Domain userDomain;
	protected Domain roleDomain;
	protected Domain privilegeDomain;
	protected Nav nav;
	
	public ShiroConfigGenerator(){
		super();
		super.fileName = "ShiroConfig.java";
	}
	
	public ShiroConfigGenerator(String packageToken){
		super();
		this.setPackageToken(packageToken);
		super.fileName = "ShiroConfig.java";
	}
	
	@Override
	public void setPackageToken(String packageToken) {
		this.packageToken = packageToken;
	}
	
	@Override
	public String generateUtilString() {
		StatementList sList = new StatementList();
		sList.add(new Statement(500L,"package "+this.getPackageToken()+".shiro;"));
		sList.add(new Statement(2000L,0,""));
		sList.add(new Statement(3000L,0,"import java.util.LinkedHashMap;"));
		sList.add(new Statement(4000L,0,"import java.util.Map;"));
		sList.add(new Statement(5000L,0,"import java.util.Properties;"));
		sList.add(new Statement(6000L,0,""));
		sList.add(new Statement(6100L,0,"import org.apache.shiro.session.mgt.SessionManager;"));
		sList.add(new Statement(7000L,0,"import org.apache.shiro.spring.web.ShiroFilterFactoryBean;"));
		sList.add(new Statement(8000L,0,"import org.apache.shiro.web.mgt.DefaultWebSecurityManager;"));
		sList.add(new Statement(9000L,0,"import org.springframework.beans.factory.annotation.Qualifier;"));
		sList.add(new Statement(10000L,0,"import org.springframework.context.annotation.Bean;"));
		sList.add(new Statement(11000L,0,"import org.springframework.context.annotation.Configuration;"));
		sList.add(new Statement(12000L,0,"import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;"));
		sList.add(new Statement(13000L,0,""));
		sList.add(new Statement(14000L,0,"import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;"));
		sList.add(new Statement(15000L,0,""));
		sList.add(new Statement(16000L,0,"@Configuration"));
		sList.add(new Statement(17000L,0,"public class ShiroConfig"));
		sList.add(new Statement(18000L,0,"{"));
		sList.add(new Statement(19000L,1,"/**"));
		sList.add(new Statement(20000L,1,"* 这个方法关联一个安全管理器"));
		sList.add(new Statement(21000L,1,"* @param defaultWebSecurityManager"));
		sList.add(new Statement(22000L,1,"* @return"));
		sList.add(new Statement(23000L,1,"*/"));
		sList.add(new Statement(24000L,1,"@Bean"));
		sList.add(new Statement(25000L,1,"public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier(\"manager\") DefaultWebSecurityManager defaultWebSecurityManager)"));
		sList.add(new Statement(26000L,1,"{"));
		sList.add(new Statement(27000L,2,"ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();"));
		sList.add(new Statement(28000L,2,"shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager); //关联安全管理器"));
		sList.add(new Statement(28100L,2,"shiroFilterFactoryBean.getFilters().put(\"authc\", new SimpleFormAuthenticationFilter());"));
		sList.add(new Statement(28200L,2,"shiroFilterFactoryBean.getFilters().put(\"perms\", new ShiroPermsAuthorizationFilter());"));
		sList.add(new Statement(28300L,2,"shiroFilterFactoryBean.getFilters().put(\"roles\", new ShiroRolesAuthorizationFilter());"));
		sList.add(new Statement(29000L,0,""));
		sList.add(new Statement(30000L,2,"/**"));
		sList.add(new Statement(31000L,2,"* 设置拦截URL"));
		sList.add(new Statement(32000L,2,"*/"));
		sList.add(new Statement(33000L,2,"Map<String, String> map = new LinkedHashMap<>();"));
		sList.add(new Statement(34000L,2,"map.put(\"/index.html\", \"anon\");"));
		sList.add(new Statement(35000L,2,"map.put(\"/images/**\", \"anon\");"));
		sList.add(new Statement(35100L,2,"map.put(\"/js/**\", \"anon\");"));
		sList.add(new Statement(35200L,2,"map.put(\"/easyui/**\", \"anon\");"));
		sList.add(new Statement(35300L,2,"map.put(\"/echarts/**\", \"anon\");"));
		sList.add(new Statement(35400L,2,"map.put(\"/uploadjs/**\", \"anon\");"));
		sList.add(new Statement(36500L,2,"map.put(\"/login/index.html\", \"anon\");"));
		sList.add(new Statement(37000L,2,"map.put(\"/login/register.html\", \"anon\");"));
		sList.add(new Statement(38000L,2,"map.put(\"/login/error.html\", \"anon\");"));
		sList.add(new Statement(38500L,2,"map.put(\"/"+this.userDomain.getControllerPackagePrefix()+"login"+this.userDomain.getControllerNamingSuffix()+"/**\", \"anon\");"));
		
		sList.add(new Statement(39000L,2,"map.put(\"/*"+this.userDomain.getControllerNamingSuffix()+"/find*\", \"authc\");"));
		sList.add(new Statement(40000L,2,"map.put(\"/*"+this.userDomain.getControllerNamingSuffix()+"/listActive*\", \"authc\");"));
		sList.add(new Statement(41000L,2,"map.put(\"/**/*.html\", \"authc\");"));
		
		sList.add(new Statement(42000L,2,"map.put(\"/"+this.userDomain.getControllerPackagePrefix()+this.roleDomain.getLowerFirstDomainName()+this.roleDomain.getControllerNamingSuffix()+"/**\", \"roles[admin]\");"));
		sList.add(new Statement(43000L,2,"map.put(\"/"+this.userDomain.getControllerPackagePrefix()+this.privilegeDomain.getLowerFirstDomainName()+this.privilegeDomain.getControllerNamingSuffix()+"/**\", \"roles[admin]\");"));
		sList.add(new Statement(44000L,2,"map.put(\"/"+this.userDomain.getControllerPackagePrefix()+this.userDomain.getLowerFirstDomainName()+this.userDomain.getControllerNamingSuffix()+"/**\", \"roles[admin]\");"));
			
		long serial = 48000L;
		Set<Domain> adminDomains = new TreeSet<>();
		adminDomains.add(this.userDomain);
		adminDomains.add(this.roleDomain);
		adminDomains.add(this.privilegeDomain);
		if (this.nav.getDomains()!=null&&this.nav.getDomains().size()>0) {
			Set<Domain> myDomains = this.nav.getDomains();
			for (Domain d:myDomains) {
				if (!DomainUtil.inDomainSet(d,adminDomains)) {
					sList.add(new Statement(serial+1000L,2,"map.put(\"/"+d.getControllerPackagePrefix()+d.getLowerFirstDomainName()+d.getControllerNamingSuffix()+"/**\", \"perms["+d.getStandardName()+"]\");"));
					serial += 2000L;
				}
			}
		}

		sList.add(new Statement(serial+44000L,2,"shiroFilterFactoryBean.setFilterChainDefinitionMap(map);"));
		sList.add(new Statement(serial+45000L,0,""));
		sList.add(new Statement(serial+46000L,2,"shiroFilterFactoryBean.setLoginUrl(\"/login/index.html\");"));
		sList.add(new Statement(serial+47000L,2,"shiroFilterFactoryBean.setUnauthorizedUrl(\"/login/noauth.html\");"));
		sList.add(new Statement(serial+48000L,0,""));
		sList.add(new Statement(serial+49000L,2,"return  shiroFilterFactoryBean;"));
		sList.add(new Statement(serial+50000L,1,"}"));
		sList.add(new Statement(serial+51000L,1,""));
		sList.add(new Statement(serial+52000L,1,"/**"));
		sList.add(new Statement(serial+53000L,1,"* 解决： 无权限页面不跳转 shiroFilterFactoryBean.setUnauthorizedUrl(\"/unauthorized\") 无效"));
		sList.add(new Statement(serial+54000L,1,"* shiro的源代码ShiroFilterFactoryBean.Java定义的filter必须满足filter instanceof AuthorizationFilter，"));
		sList.add(new Statement(serial+55000L,1,"* 只有perms，roles，ssl，rest，port才是属于AuthorizationFilter，而anon，authcBasic，auchc，user是AuthenticationFilter，"));
		sList.add(new Statement(serial+56000L,1,"* 所以unauthorizedUrl设置后页面不跳转 Shiro注解模式下，登录失败与没有权限都是通过抛出异常。"));
		sList.add(new Statement(serial+57000L,1,"* 并且默认并没有去处理或者捕获这些异常。在SpringMVC下需要配置捕获相应异常来通知用户信息"));
		sList.add(new Statement(serial+58000L,1,"* @return"));
		sList.add(new Statement(serial+59000L,1,"*/"));
		sList.add(new Statement(serial+60000L,1,"@Bean"));
		sList.add(new Statement(serial+61000L,1,"public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {"));
		sList.add(new Statement(serial+62000L,2,"SimpleMappingExceptionResolver simpleMappingExceptionResolver=new SimpleMappingExceptionResolver();"));
		sList.add(new Statement(serial+63000L,2,"Properties properties=new Properties();"));
		sList.add(new Statement(serial+64000L,2,"//这里的 /unauthorized 是页面，不是访问的路径"));
		sList.add(new Statement(serial+65000L,2,"properties.setProperty(\"org.apache.shiro.authz.UnauthorizedException\",\"/unauthorized\");"));
		sList.add(new Statement(serial+66000L,2,"properties.setProperty(\"org.apache.shiro.authz.UnauthenticatedException\",\"/unauthorized\");"));
		sList.add(new Statement(serial+67000L,2,"simpleMappingExceptionResolver.setExceptionMappings(properties);"));
		sList.add(new Statement(serial+68000L,2,"return simpleMappingExceptionResolver;"));
		sList.add(new Statement(serial+69000L,1,"}"));
		sList.add(new Statement(serial+70000L,1,""));
		sList.add(new Statement(serial+71000L,1,"/**"));
		sList.add(new Statement(serial+72000L,1,"* 获得一个安全管理器"));
		sList.add(new Statement(serial+73000L,1,"* 这个方法关联一个realm类"));
		sList.add(new Statement(serial+74000L,1,"* @param userRealm"));
		sList.add(new Statement(serial+75000L,1,"* @return"));
		sList.add(new Statement(serial+76000L,1,"*/"));
		sList.add(new Statement(serial+77000L,1,"@Bean(name = \"manager\")"));
		sList.add(new Statement(serial+78000L,1,"public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier(\"realm\") UserRealm userRealm)"));
		sList.add(new Statement(serial+79000L,1,"{"));
		sList.add(new Statement(serial+80000L,2,"DefaultWebSecurityManager manager = new DefaultWebSecurityManager();"));
		sList.add(new Statement(serial+81000L,2,"manager.setRealm(userRealm); //设置realm"));
		sList.add(new Statement(serial+81500L,2,"manager.setSessionManager(getSessionManager());"));
		sList.add(new Statement(serial+82000L,0,""));
		sList.add(new Statement(serial+83000L,2,"return manager;"));
		sList.add(new Statement(serial+84000L,1,"}"));
		sList.add(new Statement(serial+85000L,0,""));
		sList.add(new Statement(serial+86000L,1,"/**"));
		sList.add(new Statement(serial+87000L,1,"* 获得一个realm类"));
		sList.add(new Statement(serial+88000L,1,"* @return"));
		sList.add(new Statement(serial+89000L,1,"*/"));
		sList.add(new Statement(serial+90000L,1,"@Bean(name = \"realm\")"));
		sList.add(new Statement(serial+91000L,1,"public UserRealm getRealm()"));
		sList.add(new Statement(serial+92000L,1,"{"));
		sList.add(new Statement(serial+93000L,2,"return new UserRealm();"));
		sList.add(new Statement(serial+94000L,1,"}"));
		sList.add(new Statement(serial+95000L,0,""));
		sList.add(new Statement(serial+96000L,1,"@Bean(name = \"shiroDialect\")"));
		sList.add(new Statement(serial+97000L,1,"public ShiroDialect getShiroDialect()"));
		sList.add(new Statement(serial+98000L,1,"{"));
		sList.add(new Statement(serial+99000L,2,"return new ShiroDialect();"));
		sList.add(new Statement(serial+100000L,1,"}"));
		
		sList.add(new Statement(serial+101000L,1,"//添加bean"));
		sList.add(new Statement(serial+102000L,1,"/**"));
		sList.add(new Statement(serial+103000L,1,"* 自定义sessionManager"));
		sList.add(new Statement(serial+104000L,1,"* @return"));
		sList.add(new Statement(serial+105000L,1,"*/"));
		sList.add(new Statement(serial+106000L,1,"@Bean"));
		sList.add(new Statement(serial+107000L,1,"public SessionManager getSessionManager(){"));
		sList.add(new Statement(serial+108000L,2,"MySessionManager shiroSessionManager = new MySessionManager();"));
		sList.add(new Statement(serial+109000L,2,"//这里可以不设置。Shiro有默认的session管理。如果缓存为Redis则需改用Redis的管理"));
		sList.add(new Statement(serial+110000L,2,"//shiroSessionManager.setSessionDAO(new EnterpriseCacheSessionDAO());"));
		sList.add(new Statement(serial+111000L,2,"return shiroSessionManager;"));
		sList.add(new Statement(serial+112000L,1,"}"));
		
		sList.add(new Statement(serial+114000L,0,"}"));
		return sList.getContent();
	}

	public Domain getUserDomain() {
		return userDomain;
	}

	public void setUserDomain(Domain userDomain) {
		this.userDomain = userDomain;
	}

	public Domain getRoleDomain() {
		return roleDomain;
	}

	public void setRoleDomain(Domain roleDomain) {
		this.roleDomain = roleDomain;
	}

	public Domain getPrivilegeDomain() {
		return privilegeDomain;
	}

	public void setPrivilegeDomain(Domain privilegeDomain) {
		this.privilegeDomain = privilegeDomain;
	}

	public Nav getNav() {
		return nav;
	}

	public void setNav(Nav nav) {
		this.nav = nav;
	}

	
	public String getTranslateRefers(Set<Domain> targets,Domain domain) {
		Map<Domain,Set<Domain>> tanslateReferMap = new TreeMap<>();
		for (Domain target:targets) {
			for (Field f: target.getFields()) {
				if (f instanceof Dropdown) {
					Dropdown dp = (Dropdown)f;
					if (!target.getStandardName().equals(dp.getTarget())) {
						Set<Domain> refers = tanslateReferMap.get(dp.getTarget());
						if (refers == null) refers= new TreeSet<Domain>();					
						refers.add(target);
						tanslateReferMap.put(dp.getTarget(), refers);	
					}
				}
			}
		}
		Set<Domain> retVal = tanslateReferMap.get(domain);
		String retstr = "";
		if (retVal!=null) {
			retVal.remove(domain);
			for (Domain d:retVal) {
				retstr = retstr + d.getStandardName()+",";
			}
		}
		if (retstr.contains(",")) retstr = retstr.substring(0,retstr.length()-1);
		return retstr;
	}

}
